package com.jstyle.jclife.activity;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;


import com.jstyle.jclife.R;
import com.jstyle.jclife.ble.BleManager;
import com.jstyle.jclife.ble.BleService;
import com.jstyle.jclife.model.BleData;
import com.jstyle.jclife.utils.ResolveData;
import com.jstyle.jclife.utils.RxBus;
import com.jstyle.jclife.utils.SharedPreferenceUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

/**
 * 资源文件升级
 */
public class ResUpdateActivity extends Activity {
    private static final String TAG = "ResUpdateActivity";


    @BindView(R.id.progressbar_file)
    ProgressBar progressbarFile;
    @BindView(R.id.tv_progress)
    TextView tvProgress;
    private Disposable subscription;
    private ProgressDialog progressDialog;
    private String address;
    private String md5FileName = "color565MD5.txt";
    private String binFileName = "color565.bin";
    int maxLength = MainActivity.phoneDataLength;//手机一次能发送的最大数据长度
    static final byte cmdCheck = (byte) 0x90;
    static final byte cmdSend = (byte) 0x91;
    private byte[] binByte;

    String md5String;
    //private int[] binInt;
    private HashMap<Integer, byte[]> hashMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_res_update);
        ButterKnife.bind(this);
        init();
    }

    private void init() {
        initByteValue();
        if (TextUtils.isEmpty(address)) {
            Log.i(TAG, "onCreate: address null ");

        }
      //  BleManager.getInstance().connectDevice(address);
     //   showConnectDialog();
        subscription = RxBus.getInstance().toObservable(BleData.class).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<BleData>() {
            @Override
            public void accept(BleData data) throws Exception {
                String action = data.getAction();
                if (BleService.ACTION_GATT_onDescriptorWrite.equals(action)) {

                    dissMissDialog();
                } else if (BleService.ACTION_GATT_DISCONNECTED.equals(action)) {

                    dissMissDialog();
                } else if (BleService.ACTION_DATA_AVAILABLE.equals(action)) {
                   // Log.i(TAG, "accept: " + ResolveData.byte2Hex(data.getValue()));
                    resolveData(data.getValue());
                }
            }
        });
        showProgressView(true);
        startUpdate();
    }

    private void resolveData(byte[] value) {
        switch (value[0]) {
            case cmdCheck:
                if (value[1] == 1) {//查询是否需要升级
                    if(hashMap==null)return;
                    sendData = hashMap.get(packageCount);
                    if(sendData==null)return;
                    crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
                    startUpdate();
                    startTime=System.currentTimeMillis();
                    showProgressView(true);
                    if (value[2] == 0) {//不需要升级
                        Log.i(TAG, "resolveData: 不需要升级");
                    } else if (value[2] == 1) {//需要升级
                        //startUpdate();
                    } else if (value[2] == 2) {//固件没有升级
                        Log.i(TAG, "resolveData: 需要先升级固件文件");
                    }
                } else if (value[1] == 2) {//升级数据发送完成
                    Log.i(TAG, "resolveData: "+(System.currentTimeMillis()-startTime));
                    showProgressView(false);
                    String info="";
                    long time=System.currentTimeMillis()-startTime;
                    if (value[2] == 0) {//失败
                        info=getString(R.string.res_update_failed);
                        //Log.i(TAG, "resolveData: 升级失败");
                    } else if (value[2] == 1) {//成功
                        info=getString(R.string.res_update_successFul);
                        // Log.i(TAG, "resolveData: 升级成功");
                    }
                    showUpdateStatus(info);

                } else if (value[1] == 3) {
                    Log.i(TAG, "resolveData: crc检测");
                } else if (value[1] == 0x10) {//超时
                    Log.i(TAG, "resolveData: 超时");
                }
                break;

            case cmdSend:
                if (value[1] == 1) {
                    isFinish = false;
                    packageCount++;
                    sendData = hashMap.get(packageCount);
                    updateProgress();
                    if (sendData == null) {
                        endUpdateFile();
                    } else {
                        crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
                        startUpdate();
                    }

                } else if (value[1] == 0) {
                    Log.i(TAG, "resolveData: 重发" + packageCount);
                    isFinish = false;
                    sendData = hashMap.get(packageCount);
                    crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
                    sendTotalPackage = sendTotalPackage - sendData.length;
                    startUpdate();
                }
                break;
        }


    }
    long startTime;
    private void showUpdateStatus(String info){
        AlertDialog alertDialog=new AlertDialog.Builder(this)
                .setTitle(R.string.res_update)
                .setMessage(info)
                .setCancelable(false)
                .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })
                .create();
        alertDialog.show();
    }
    private void showProgressView(boolean enable) {
        tvProgress.setVisibility(enable?View.VISIBLE:View.GONE);
        progressbarFile.setVisibility(enable?View.VISIBLE:View.GONE);
        progressbarFile.setIndeterminate(enable);
    }

    private void updateProgress() {
        float send=sendTotalPackage;
        float total=binByte.length;
        float percent=send/total;
        NumberFormat format= NumberFormat.getPercentInstance();
        format.setMaximumFractionDigits(0);
        tvProgress.setText(format.format(percent));
        progressbarFile.setIndeterminate(false);
        progressbarFile.setProgress((int) (percent*100));
    }

    int packageCount;//块编号
    int Count;//包编号
    int sendTotalPackage;//块发送长度
    int sendTotal;//总发送长度
    boolean isFinish;//本块数据发送是否完成
    boolean isSendFinish;//所有数据发送是否完成
    byte[] sendData;//发送的数据块
    int crcCount;//本块数据的crc
    List<Integer> list;


    private void startUpdate() {
        if (maxLength == 0 || isFinish) return;
        if (sendData == null) {
            endUpdateFile();
            return;
        }
        int dataLength = sendData.length;//要发送的数据块的长度
        //一次包发送数据长度，cmd(1)+块编号(1)+包编号(1)+crc(2)+(块最后一包时加上本块crc(2))
        int contentLength = isFinish ? maxLength - 7 : maxLength - 5;
        isFinish = false;
        if (sendTotal + contentLength >= dataLength) {//块数据发送完毕
            contentLength = dataLength - sendTotal;
            sendTotal = 0;
            isFinish = true;
        } else {
            sendTotal += contentLength;
        }
        if (sendTotalPackage + contentLength >= binByte.length) {//发送完毕
            contentLength = binByte.length - sendTotalPackage;
            isSendFinish = true;
        }
        int length = isFinish ? contentLength + 7 : contentLength + 5;
        byte[] value = new byte[length];
        value[0] = (byte) 0x91;
        value[1] = (byte) packageCount;
        value[2] = (byte) Count++;
        System.arraycopy(binByte, sendTotalPackage, value, 3, contentLength);
        if (isFinish) {
            value[value.length - 4] = (byte) ((crcCount) & 0xff);
            value[value.length - 3] = (byte) ((crcCount >> 8) & 0xff);
        }
        int crc16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[value.length - 2] = (byte) ((crc16) & 0xff);
        value[value.length - 1] = (byte) ((crc16 >> 8) & 0xff);
        sendTotalPackage += contentLength;
        //Log.i(TAG, "startUpDate: l " + sendTotalPackage);
        BleManager.getInstance().offerValue(value);
        if (isFinish) {
            Count = 0;
            BleManager.getInstance().offerValue((getEnd(packageCount, crcCount)));
            BleManager.getInstance().writeValue();
        } else {
            //   BleManager.getInstance().writeValue(value);
            startUpdate();
        }

    }

    private byte[] getEnd(int count, int crc) {//每块数据发送完成后请求检验数据正确性
        byte[] value = new byte[7];
        value[0] = cmdSend;
        value[1] = (byte) count;
        value[2] = (byte) 0xff;
        value[3] = (byte) ((crc) & 0xff);
        value[4] = (byte) ((crc >> 8) & 0xff);
        int crc16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[5] = (byte) ((crc16) & 0xff);
        value[6] = (byte) ((crc16 >> 8) & 0xff);
        return value;
    }
//    List<byte[]>valueList;
//    private void forUpdate(){
//        for(byte[]value:valueList){
//            int length=value.length;
//
//        }
//    }


    private void dissMissDialog() {
        if (progressDialog != null && progressDialog.isShowing()) progressDialog.dismiss();
        ;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unsubscribe();
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        if (BleManager.getInstance().isConnected())
            BleManager.getInstance().disconnectDevice();
    }

    private void unsubscribe() {
        if (subscription != null && !subscription.isDisposed()) {
            subscription.dispose();
            Log.i(TAG, "unSubscribe: ");
        }
    }

    private void showConnectDialog() {
        progressDialog = new ProgressDialog(this);
        progressDialog.setMessage(getString(R.string.connectting));
        // progressDialog.setCancelable(false);
        if (!progressDialog.isShowing()) progressDialog.show();

    }

    private String loadFromSDFile(String fileName) {

        String result = null;
        try {
            File f = new File(fileName);
            int length = (int) f.length();
            byte[] buff = new byte[length];
            FileInputStream fin = new FileInputStream(f);
            fin.read(buff);
            fin.close();
            result = new String(buff, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private byte[] readFile(File file) {
        // 需要读取的文件，参数是文件的路径名加文件名
        if (file.isFile()) {
            // 以字节流方法读取文件
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                // 设置一个，每次 装载信息的容器
                byte[] buffer = new byte[1024];
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                // 开始读取数据
                int len = 0;// 每次读取到的数据的长度
                while ((len = fis.read(buffer)) != -1) {// len值为-1时，表示没有数据了
                    // append方法往sb对象里面添加数据
                    outputStream.write(buffer, 0, len);
                }
                // 输出字符串
                return outputStream.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("文件不存在！");
        }
        return null;
    }


    private void initByteValue() {
        String path= SharedPreferenceUtils.getSpString(SharedPreferenceUtils.KEY_RES_FILEPATH);
        File binFile = new File(path + "color565.bin");
        binByte = readFile(binFile);
      //  readDataFile();
        int length = binByte.length % 4096 == 0 ? binByte.length / 4096 : binByte.length / 4096 + 1;
        hashMap = new HashMap<>();
        Log.i(TAG, "initByteValue: " + length);
        for (int i = 0; i < length; i++) {//数据分块，一块4096长度
            int valueLength = 4096;
            if (i * 4096 + valueLength > binByte.length) {
                valueLength = binByte.length - i * 4096;
            }
            byte[] value = new byte[valueLength];
            System.arraycopy(binByte, i * 4096, value, 0, valueLength);
            hashMap.put(i, value);
        }
        sendData = hashMap.get(packageCount);
        crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
        startTime= System.currentTimeMillis();
    }

    private void deleteFile() {//删除资源文件
        byte[] value = new byte[4];
        value[0] = cmdCheck;
        value[1] = 0x70;
        int crc16 = ResolveData.CalcCRC16(value, 2);
        value[2] = (byte) ((crc16) & 0xff);
        value[3] = (byte) ((crc16 >> 8) & 0xff);
        BleManager.getInstance().writeValue(value);
    }


    private void endUpdateFile() {//数据全部发送完成检查是否升级成功
        String path= SharedPreferenceUtils.getSpString(SharedPreferenceUtils.KEY_RES_FILEPATH);

        File binFile = new File(path + "color565.bin");
        byte[] binByte = readFile(binFile);
        String md5String = loadFromSDFile(path+md5FileName);
        byte[] binMd5 = getMd5Byte(md5String.trim());
        int length = binByte.length;
        int crc16 = ResolveData.CalcCRC16(binByte, binByte.length);
        byte[] value = new byte[26];
        value[0] = cmdCheck;
        value[1] = 02;
        value[2] = (byte) ((length) & 0xff);//低位在前
        value[3] = (byte) ((length >> 8) & 0xff);
        value[4] = (byte) ((length >> 16) & 0xff);
        value[5] = (byte) ((length >> 24) & 0xff);
        System.arraycopy(binMd5, 0, value, 6, binMd5.length);
        value[22] = (byte) ((crc16) & 0xff);
        value[23] = (byte) ((crc16 >> 8) & 0xff);
        int crcValue16 = ResolveData.CalcCRC16(value, 24);
        value[24] = (byte) ((crcValue16) & 0xff);
        value[25] = (byte) ((crcValue16 >> 8) & 0xff);
        BleManager.getInstance().writeValue(value);
    }

    private byte[] getMd5Byte(String md5String) {
        int length = md5String.length() / 2;
        byte[] value = new byte[length];
        for (int i = 0; i < length; i++) {
            String s = md5String.substring(i * 2, i * 2 + 2);
            value[i] = getByte(s);
        }
        return value;
    }

    private byte getByte(String trim) {
        if (TextUtils.isEmpty(trim)) return 0;
        return (byte) Integer.parseInt(trim, 16);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK){
            return false;
        }
        return super.onKeyDown(keyCode, event);
    }
}
